package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.http.MessageConstraintException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnTransitEntity;
import com.foreveross.crawl.exception.FlightsNotPriceException;
import com.foreveross.crawl.util.DateUtil;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
 * 2014-09-24
 * https://www.koreanair.com/global/zh_cn.html
 */
public class KoreanAirAdapter extends AbstractAdapter {

	public KoreanAirAdapter(TaskModel taskQueue) {
		super(taskQueue);
	}

	//舱位
	private static final Map<String,String> cabins = new LinkedHashMap<String, String>();
	{
		cabins.put("ECONOMY", "经济舱");
		cabins.put("PRESTIGE", "商务舱");
		cabins.put("FIRST", "头等舱");
	}
	
	@Override
	public Object fetch(String arg0) throws Exception {
		switch (super.getRouteType()) {
		case INTERNATIONAL_ROUND:
			return fetchDI();//国际往返
		}
		return null;
	}

	
	/**
	 * 国际往返 
	 * @return 
	 */
	private Object fetchDI() {
		//存储舱位对应的数据（JSON）
		Map<String,String> datas=Maps.newHashMap();
		HttpGet g=null;
		HttpClient httpClient = this.getHttpClient();
		for(String cabinType:cabins.keySet()){
			String url=getInterDouUrl(cabinType);
			logger.info(String.format("获取【%s】舱位航班信息...", cabinType));
			g= new HttpGet(url);
			setRequestHeadInfo(g);
			try {
				String page="";
				page= excuteRequest(httpClient, g, "gb2312");
				if(page !=null && !page.equals("")){
					logger.info(String.format("【%s】舱位航班信息获取成功", cabinType));
					datas.put(cabinType, page);
					/*if(page.length()<2000){//没有此航班日期
						logger.info(String.format("【%s】舱位航班信息有误:【%s】", cabinType,JSONObject.fromObject(page).getString("message")));
						continue;
					}else{
						logger.info(String.format("【%s】舱位航班信息获取成功", cabinType));
						datas.put(cabinType, page);
					}*/
				}
			} catch (Exception e) {
				if(datas.size()>0){
					//保存页面相关信息
					String sources="";
					for(String str:datas.keySet()){
						sources+=datas.get(str);
					}
					super.appendPageContents(sources);//存入网页原数据
					super.setLenghtCount(sources.length());//存入网页原数据
					return datas;
				}else{
					logger.error(String.format("抓取失败放弃此舱位信息【%s】",cabinType));
					continue;
				}
			}
		}
		
		//保存页面相关信息
		String sources="";
		for(String str:datas.keySet()){
			sources+=datas.get(str);
		}
		super.appendPageContents(sources);//存入网页原数据
		super.setLenghtCount(sources.length());//存入网页原数据
		
		return datas;
	}

	/**
	 * 国际往返URL
	 * @return
	 */
	public String getInterDouUrl(String cabinType){
		StringBuffer url=new StringBuffer("https://www.koreanair.com/api/fly/revenue/from");
		url.append("/"+taskQueue.getFromCity());
		url.append("/to");
		url.append("/"+taskQueue.getToCity());
		url.append("/on");
		url.append("/"+taskQueue.getFlightDate().substring(5,7)+"-"+taskQueue.getFlightDate().substring(8,10)+"-"+taskQueue.getFlightDate().substring(0,4));
		url.append("/from");
		url.append("/"+taskQueue.getToCity());
		url.append("/to");
		url.append("/"+taskQueue.getFromCity());
		url.append("/on");
		url.append("/"+taskQueue.getReturnGrabDate().substring(5,7)+"-"+taskQueue.getReturnGrabDate().substring(8,10)+"-"+taskQueue.getReturnGrabDate().substring(0,4));
		url.append("?flexDays=0");
		url.append("&");
		url.append("scheduleDriven=false");
		url.append("&");
		url.append("purchaseThirdPerson=");
		url.append("&");
		url.append("domestic=false");
		url.append("&");
		url.append("adults=1");
		url.append("&");
		url.append("children=0");
		url.append("&");
		url.append("infants=0");
		url.append("&");
		url.append("cabinClass="+cabinType);
		url.append("&");
		url.append("adultDiscounts=");
		url.append("&");
		url.append("adultInboundDiscounts=");
		url.append("&");
		url.append("childDiscounts=");
		url.append("&");
		url.append("childInboundDiscounts=");
		url.append("&");
		url.append("infantDiscounts=");
		url.append("&");
		url.append("infantInboundDiscounts=");
		url.append("&");
		url.append("_="+new Date().getTime());
		return url.toString();
	}
			
	/**
	 * 设置请求头信息
	 * @param get
	 */
	private void setRequestHeadInfo(HttpRequestBase g) {
		g.setHeader("Host", "www.koreanair.com");
		g.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0");
		g.setHeader("Accept","	text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		g.setHeader("Accept-Language", "zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3");
	}

	@Override
	public String getUrl() throws Exception {
		return null;
	}

	@Override
	public List<Object> paraseToVo(Object obj) throws Exception {
		switch (super.getRouteType()) {
		case INTERNATIONAL_ROUND:
			return paraseToVoDI(obj);//国际往返
		}
		return null;
	}

	
	/**
	 * 解析国际往返
	 * @param obj
	 * @return
	 * @throws Exception 
	 */
	private List<Object> paraseToVoDI(Object obj) throws Exception {
		Map<String,String> data=(Map<String, String>) obj;
		if(data.size()>0){
			Map<String,List<String>>allLines=Maps.newHashMap();//总航线信息
			Map<String,List<FlightInfo>> allInfos=Maps.newHashMap();//存储航班基本信息
			Map<String ,CabinInfo> priceMap=Maps.newHashMap();//存储价格相关信息
			Map<String,String> canbInfo=Maps.newHashMap();//存储key对应的舱位信息
			int countCabin = 0;
				try{
					for(String key:data.keySet()){
						String source=data.get(key);
						JSONObject json=JSONObject.fromObject(source);
						try{
							if(source.length()<2000){
								if(json.getString("message") !=null){
									countCabin++;
									throw new FlightsNotPriceException(String.format("该【%s】舱位下没有航班计划", key));
								}
							}
						}catch (Exception e) {
							if(countCabin == data.keySet().size()) throw e;
							else continue;
						}
						//去程信息
						JSONArray gjsons=json.getJSONArray("outbound");
						for(int i=0;i<gjsons.size();i++){
							JSONObject flighBaseInfo=gjsons.getJSONObject(i);
							buildFlightInfos(flighBaseInfo,allInfos);
						}
						
						//回程信息
						JSONArray rjsons=json.getJSONArray("inbound");
						for(int i=0;i<rjsons.size();i++){
							JSONObject flighBaseInfo=rjsons.getJSONObject(i);
							buildFlightInfos(flighBaseInfo,allInfos);
						}
						
						//价格信息
						JSONObject pricejson=json.getJSONObject("fares");
						getPriceStr(pricejson,priceMap,canbInfo);
						
						//总航线信息
						JSONObject totalJsonF=json.getJSONObject("tripFareMapper");//总航班信息
						getAllFlights(totalJsonF,allLines);
						
					}
				}catch (Exception e) {
				e.printStackTrace();
			}
			List<AbstractPlaneInfoEntity> list=new ArrayList<AbstractPlaneInfoEntity>();
			//组装一条航线完整信息
			try{
				 if(allLines.size()>0){
					for(Map.Entry<String, List<String>> line:allLines.entrySet()){
						DoublePlaneInfoEntity entity=null;
						ReturnDoublePlaneInfoEntity rEntity=null;
						String lineKey=line.getKey();//对应航班信息
						List<String>priceLists=line.getValue();//对应价格信息
						String[]lines=lineKey.split("\\-");
						if(lines.length==2){//往返正确情况下只有两个
							//去,回程航班组
							String gKey=lines[0],rKey=lines[1];
							List<FlightInfo>gInfos=allInfos.get(gKey);//去程信息
							List<FlightInfo>rInfos=allInfos.get(rKey);//回程信息
							
							//去程实体
							entity=PlaneInfoEntityBuilder.buildPlaneInfo(
									taskQueue, "KE", "大韩航空", "大韩航空公司",gInfos.get(0).getTstartTime(),gInfos.get(0).getTendTime(), gInfos.get(0).getFlightNo(), null, null, null, gInfos.get(0).getFlightType(), DoublePlaneInfoEntity.class);
							if(gInfos.size()>1){//说明去程有中转
								//组装去程中转
								for(FlightInfo gT:gInfos){
									TransitEntity trEntity=null;//去程中转
									trEntity=PlaneInfoEntityBuilder.buildTransitEntity(
											gT.getFlightNo(), null, "KE", "大韩航空", "大韩航空公司", 
											gT.getFromAirport(), null, gT.getToAirport(), null, gT.getFlightType(),TransitEntity.class);
									trEntity.setStartTime(DateUtil.string2Date(gT.getStartTime(), "yyyy-MM-dd HH:mm:ss"));
									trEntity.setEndTime(DateUtil.string2Date(gT.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
									if(gT.getFlightDuration()!=null){
										entity.setFlightDuration(gT.getFlightDuration());
									}
									entity.getTransits().add(trEntity);//增加中转信息到中转实体中
								}
							}
							
							//回程实体
							rEntity=PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, "KE","大韩航空", "大韩航空公司", rInfos.get(0).getTstartTime(), rInfos.get(0).getTendTime(), rInfos.get(0).getFlightNo(), null, null, null, rInfos.get(0).getFlightType(),ReturnDoublePlaneInfoEntity.class);
							if(rInfos.size()>1){//说明回程有中转
								//组装返程中转
								for(FlightInfo rT:rInfos){
									ReturnTransitEntity rTr=PlaneInfoEntityBuilder.buildTransitEntity(
											rT.getFlightNo(), null, "KE","大韩航空", "大韩航空公司", 
											rT.getFromAirport(), null, rT.getToAirport(), null, rT.getFlightType(),ReturnTransitEntity.class);
									rTr.setStartTime(DateUtil.string2Date(rT.getStartTime(),"yyyy-MM-dd HH:mm"));
									rTr.setEndTime(DateUtil.string2Date(rT.getEndTime(),"yyyy-MM-dd HH:mm"));
									if(rT.getFlightDuration() !=null){
										rEntity.setFlightDuration(rT.getFlightDuration());
									}
									rEntity.getReturnTransits().add(rTr);
								}
							}
							
							//处理价格信息（包括舱位）
							List<Double> totalLists=Lists.newArrayList();//存储总价
							List<Double> noteLists=Lists.newArrayList();//存储裸价
							List<Double> taxLists=Lists.newArrayList();//存储税价
							if(priceLists.size()>0){
								for(String priceKey:priceLists){
									CabinInfo priceInfo=priceMap.get(priceKey);
									String canbinClass=priceInfo.getCabinClass();
									Double totalPrice= priceInfo.getTotalPrice();
									Double taxPrice=priceInfo.getTaxPrice();
									Double notePrice=priceInfo.getNakePirce();
									totalLists.add(totalPrice);
									noteLists.add(notePrice);
									taxLists.add(taxPrice);
									//处理舱位信息(...)
									CabinEntity cabinEntity=new CabinEntity();//去程舱位信息
									cabinEntity.setCabinType(canbinClass);
									cabinEntity.setPrice(totalPrice);
									entity.getCabins().add(cabinEntity);
									//回程舱位
									ReturnCabinEntity rCabinE=PlaneInfoEntityBuilder.buildCabinInfo(
											canbinClass, null, null,totalPrice+"", null, null, null, ReturnCabinEntity.class);
									rEntity.getReturnCabins().add(rCabinE);
								}
							}
							
							//处理得到各种最高最低价
							rEntity.setSumHighestPrice(getHL(totalLists).get(0));
							rEntity.setSumLowestPrice(getHL(totalLists).get(1));
							rEntity.setTotalHighestPrice(getHL(noteLists).get(0));
							rEntity.setTotalLowestPrice(getHL(noteLists).get(1));
							rEntity.setTotalHighestTaxesPrice(getHL(taxLists).get(0));
							rEntity.setTotalLowestTaxesPrice(getHL(taxLists).get(1));
							
							entity.setSumHighestPrice(getHL(totalLists).get(0));
							entity.setSumLowestPrice(getHL(totalLists).get(1));
							entity.setTotalHighestPrice(getHL(noteLists).get(0));
							entity.setTotalLowestPrice(getHL(noteLists).get(1));
							entity.setTotalHighestTaxesPrice(getHL(taxLists).get(0));
							entity.setTotalLowestTaxesPrice(getHL(taxLists).get(1));
							entity.getReturnPlaneInfos().add(rEntity);
							list.add(entity);
						}
						
					}
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
			
			return Arrays.asList(list.toArray());
		}
		return null;
	}

	
	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		if(fetchObject == null){
			return false;
		}else if(fetchObject instanceof JSONObject){
			if(fetchObject.toString().length()<2000){
				throw new MessageConstraintException("抓取的数据不正确(长度少于2000)");
			}
		}
		return true;
	}


	/**
	 * 
	 * @param table  每一段航班，去程或回程
	 * @return
	 * @throws ParseException 
	 */
	private void buildFlightInfos(JSONObject jsonAr,Map<String,List<FlightInfo>>maps) {
		List<FlightInfo> list = new ArrayList<FlightInfo>();
		String TstartTimeStr=jsonAr.getString("departure").split("\\.")[0].replaceAll("T", " ");
		String TendTimeStr=jsonAr.getString("arrival").split("\\.")[0].replaceAll("T", " ");
		JSONArray flighJA=jsonAr.getJSONArray("flights");//航班基本信息
		if(flighJA.size()>0){
			String key="";
			for(int i=0;i<flighJA.size();i++){
				JSONObject fliJson=flighJA.getJSONObject(i);
				key+=fliJson.getString("flightNumber");
			}
			if(maps.get(key)!=null){
				return ;
			}else{
				for(int i=0;i<flighJA.size();i++){
					JSONObject fliJson=flighJA.getJSONObject(i);
					FlightInfo fl=new FlightInfo();
					fl.setTstartTime(TstartTimeStr);
					fl.setTendTime(TendTimeStr);
					fl.setFlightNo(fliJson.getString("flightNumber"));
					fl.setFromAirport(fliJson.getString("departureAirportCode"));
					fl.setToAirportName(fliJson.getString("destinationAirportCode"));
					fl.setStartTime(fliJson.getString("departure").split("\\.")[0].replaceAll("T", " "));
					fl.setEndTime(fliJson.getString("arrival").split("\\.")[0].replaceAll("T", " "));
					fl.setFlightType(fliJson.getString("aircraftName"));
					try{
						fl.setFlightDuration(fliJson.getString("flightTime")!=null?fliJson.getLong("flightTime"):0l);
					}catch (Exception e) {
					}
					list.add(fl);
				}	
				maps.put(key, list);
			}
		}
	}
	
	/**
	 * 统计出是低，最高价格
	 * @return
	 */
	public List<Double> getHL(List<Double> prices){
		List<Double> priceLists=Lists.newArrayList();
		if(prices.size()>0){
			Double h=0.0,l=9999999.0;
			for(Double price:prices){
				if(price<l){
					l=price;
				}
				if(price>h){
					h=price;
				}
			}
			priceLists.add(h);
			priceLists.add(l);
			return priceLists;
		}
		return null;
	}
	
	
	/**
	 * 解析对应的总航线关系图
	 * @return 
	 */
	public void getAllFlights(JSONObject jsonAr,Map<String,List<String>>flightMap){
		if(jsonAr.size()>0){
			Iterator it=jsonAr.keySet().iterator();
			while(it.hasNext()){
				List<String> priceStr=Lists.newArrayList();
				String key=it.next().toString();
				String flightNoKey=getLine(key);
				JSONArray linesAr=jsonAr.getJSONArray(key);
				if(linesAr.size()>0){
					for(int i=0;i<linesAr.size();i++){
						priceStr.add(linesAr.get(i).toString());
					}
					flightMap.put(flightNoKey, priceStr);
				}
			}
		}
	}
	
	//解析出对应的航班号
	//20141002-KE854-KE093-1-0001ZxzMpFRDkCEXfJDBwhBoQ1v:18lf0a07k-20141030-KE094-KE2851-0-0001ZxzMpFRDkCEXfJDBwhBoQ1v:18lf0a07k-FIRST
	public String getLine(String str){
		if(str !=null && !str.equals("")){
			String key="";
			String keys[]=str.split("\\:");
			if(keys.length>0){
				int k=0;
				for(int i=0;i<keys.length;i++){
					String keyStr=keys[i];
					List<String> flignKeys=getPatternList(keyStr, "(KE\\d{3,5})","","");
					if(flignKeys.size()>0){
						if(k!=i){
							key=key+"-";
						}
						for(String s:flignKeys){
							key+=s;
						}
					}
				}
				return key;
			}
		}
		return null;
	}
	
	//正则
	private List<String> getPatternList(String content, String regEx, String replace, String replacement){
		Pattern p=Pattern.compile(regEx, Pattern.DOTALL|Pattern.MULTILINE);
		Matcher m=p.matcher(content);
		List<String> strList = new ArrayList<String>();
		while(m.find()){
			strList.add(m.group(1).trim().replaceAll(replace, replacement));
		}
		return strList;
	}
	
	/**
	 * 解析价格信息
	 * 包括对应的舱位信息
	 */
	public void getPriceStr(JSONObject jsonObj,Map<String,CabinInfo> priceInfo,Map<String,String>canbInfo){
		if(jsonObj.size()>0){
			Iterator it= jsonObj.keySet().iterator();
			while(it.hasNext()){
				String key=it.next().toString();
				JSONObject priceJso=jsonObj.getJSONObject(key);
				CabinInfo canbPrice=new CabinInfo();
				canbPrice.setCabinClass(priceJso.getString("cabinClass"));
				canbInfo.put(key, priceJso.getString("cabinClass"));
				canbPrice.setTotalPrice(priceJso.getDouble("fare"));
				JSONArray priceAr=priceJso.getJSONArray("fares");
				if(priceAr.size()>0){
					JSONObject taxPriceJso=priceAr.getJSONObject(0);
					try{
						canbPrice.setNakePirce(taxPriceJso.getDouble("amount"));
						canbPrice.setTaxPrice(taxPriceJso.getDouble("tax")+taxPriceJso.getDouble("fuelSurcharge"));
						canbPrice.setCurrencyCode(priceJso.getString("currencyCode"));
					}catch (Exception e) {
					}
				}
				priceInfo.put(key, canbPrice);
			}
		}
		
	}
	
	//航班基础信息
	private class FlightInfo{
		private String TstartTime;//出发时间
		private String TendTime;//到达时间
		private String flightNo;//航班号
		private String startTime;//起飞时间
		private String endTime;//结束时间
		private String fromAirport;//起飞城市机场
		private String toAirport;//到达城市机场
		private String fromAirportName; 
		private String toAirportName;
		private String flightType;//飞机类型
		private Long stopTime;//停留时间
		private Long flightDuration;//飞行总时间
		public String getFlightNo() {
			return flightNo;
		}
		public void setFlightNo(String flightNo) {
			this.flightNo = flightNo;
		}
		public String getTstartTime() {
			return TstartTime;
		}
		public void setTstartTime(String tstartTime) {
			TstartTime = tstartTime;
		}
		public String getTendTime() {
			return TendTime;
		}
		public void setTendTime(String tendTime) {
			TendTime = tendTime;
		}
		public String getStartTime() {
			return startTime;
		}
		public void setStartTime(String startTime) {
			this.startTime = startTime;
		}
		public String getEndTime() {
			return endTime;
		}
		public void setEndTime(String endTime) {
			this.endTime = endTime;
		}
		public String getFromAirport() {
			return fromAirport;
		}
		public void setFromAirport(String fromAirport) {
			this.fromAirport = fromAirport;
		}
		public String getToAirport() {
			return toAirport;
		}
		public void setToAirport(String toAirport) {
			this.toAirport = toAirport;
		}
		
		public String getFromAirportName() {
			return fromAirportName;
		}
		public void setFromAirportName(String fromAirportName) {
			this.fromAirportName = fromAirportName;
		}
		public String getToAirportName() {
			return toAirportName;
		}
		public void setToAirportName(String toAirportName) {
			this.toAirportName = toAirportName;
		}
		public String getFlightType() {
			return flightType;
		}
		public void setFlightType(String flightType) {
			this.flightType = flightType;
		}
		public Long getStopTime() {
			return stopTime;
		}
		public void setStopTime(Long stopTime) {
			this.stopTime = stopTime;
		}
		public Long getFlightDuration() {
			return flightDuration;
		}
		public void setFlightDuration(Long flightDuration) {
			this.flightDuration = flightDuration;
		}
	}
	
	//价格信息
	private class CabinInfo{
		private String cabinClass;
		private Double totalPrice;//总价
		private Double nakePirce;//裸价
		private Double taxPrice;//税价
		private String currencyCode;//货币单位
		public String getCabinClass() {
			return cabinClass;
		}
		public void setCabinClass(String cabinClass) {
			this.cabinClass = cabinClass;
		}
		public Double getTotalPrice() {
			return totalPrice;
		}
		public void setTotalPrice(Double totalPrice) {
			this.totalPrice = totalPrice;
		}
		public Double getNakePirce() {
			return nakePirce;
		}
		public void setNakePirce(Double nakePirce) {
			this.nakePirce = nakePirce;
		}
		public Double getTaxPrice() {
			return taxPrice;
		}
		public void setTaxPrice(Double taxPrice) {
			this.taxPrice = taxPrice;
		}
		public String getCurrencyCode() {
			return currencyCode;
		}
		public void setCurrencyCode(String currencyCode) {
			this.currencyCode = currencyCode;
		}
	}
	
}
